using UnityEngine;
using System.Collections;

public class MyMasterServer : MonoBehaviour
{
    public static MyMasterServer MS;

    private  ConnectionTesterStatus natCapable= ConnectionTesterStatus.Undetermined;
    public  int serverPort = 25002;
    public readonly string gameName = "MyCubeGame";
    public string roomName = "RYO's room";
    public string roomDescription = "Test text";
    public int maxConnections = 1;

    private float lastHostListRequest = -1000.0f;
    private float hostListRefreshTimeout = 10.0f;

    private bool useNat = true;
    private bool doneTesting = false;
    private bool probingPublicIP = false;

    private float timer = 0.0f;

    private string testMessage = "Undetermined NAT capabilities";


    private int lastLevelPrefix = 0;

    public bool canBeginGame = false;
    //new 


    void Awake()
    {
        if (MS == null)
        {
            MS = this;
        }
        else
        {
            Destroy(this.gameObject);
            return;
        }

        // Start connection test
        natCapable = Network.TestConnection();

        // What kind of IP does this machine have? TestConnection also indicates this in the
        // test results
        if (Network.HavePublicAddress())
            Debug.Log("This machine has a public IP address");
        else
            Debug.Log("This machine has a private IP address");

        DontDestroyOnLoad(this);
        networkView.group = 1;
    }

	// Use this for initialization
	void Start () {
        // If test is undetermined, keep running
        if (!doneTesting)
        {
            TestConnection();
        }
	}


    void TestConnection()
    {
        // Start/Poll the connection test, report the results in a label and react to the results accordingly
        natCapable = Network.TestConnection();
        switch (natCapable)
        {
            case ConnectionTesterStatus.Error:
                testMessage = "Problem determining NAT capabilities";
                doneTesting = true;
                break;

            case ConnectionTesterStatus.Undetermined:
                testMessage = "Undetermined NAT capabilities";
                doneTesting = false;
                break;
            case ConnectionTesterStatus.PublicIPIsConnectable:
                testMessage = "Directly connectable public IP address.";
                useNat = false;
                doneTesting = true;
                break;

            // This case is a bit special as we now need to check if we can 
            // use the blocking by using NAT punchthrough
            case ConnectionTesterStatus.PublicIPPortBlocked:
                testMessage = "Non-connectble public IP address (port " + serverPort + " blocked),"
                + " running a server is impossible.";
                useNat = false;
                // If no NAT punchthrough test has been performed on this public IP, force a test
                if (!probingPublicIP)
                {
                    Debug.Log("Testing if firewall can be circumnvented");
                    natCapable = Network.TestConnectionNAT();
                    probingPublicIP = true;
                    timer = Time.time + 10;
                }
                // NAT punchthrough test was performed but we still get blocked
                else if (Time.time > timer)
                {
                    probingPublicIP = false; // reset
                    useNat = true;
                    doneTesting = true;
                }
                break;
            case ConnectionTesterStatus.PublicIPNoServerStarted:
                testMessage = "Public IP address but server not initialized,"
                + "it must be started to check server accessibility. Restart connection test when ready.";
                break;

            case ConnectionTesterStatus.LimitedNATPunchthroughPortRestricted:
                testMessage = "Limited NAT punchthrough capabilities. Cannot " +
                    "connect to all types of NAT servers. Running a server " +
                    "is ill advised as not everyone can connect.";
                useNat = true;
                doneTesting = true;
                break;

            case ConnectionTesterStatus.LimitedNATPunchthroughSymmetric:
                testMessage = "Limited NAT punchthrough capabilities. Cannot " +
                    "connect to all types of NAT servers. Running a server " +
                    "is ill advised as not everyone can connect.";
                useNat = true;
                doneTesting = true;
                break;

            case ConnectionTesterStatus.NATpunchthroughAddressRestrictedCone:
            case ConnectionTesterStatus.NATpunchthroughFullCone:
                testMessage = "NAT punchthrough capable. Can connect to all " +
                    "servers and receive connections from all clients. Enabling " +
                    "NAT punchthrough functionality.";
                useNat = true;
                doneTesting = true;
                break;

            default:
                testMessage = "Error in test routine, got " + natCapable;
                break;
        }
    }


    public void RetestConnection()
    {
        Debug.Log("Redoing connection test");
        probingPublicIP = false;
        doneTesting = false;
        natCapable = Network.TestConnection(true);
    }

    public void StartServer()
    {
        Network.InitializeServer(maxConnections, serverPort, useNat);
        MasterServer.updateRate = 3;
        MasterServer.RegisterHost(gameName, roomName, roomDescription);
    }

    public void RefreshServers()
    {
        MasterServer.ClearHostList();
        MasterServer.RequestHostList(gameName);
    }

    public void GameBegin()
    {
        // Make sure no old RPC calls are buffered and then send load level command
        Network.RemoveRPCsInGroup(0);
        Network.RemoveRPCsInGroup(1);
        // Load level with incremented level prefix (for view IDs)
        networkView.RPC("LoadLevel", RPCMode.AllBuffered, "MyGameScene", lastLevelPrefix + 1);

    }

    public void Disconnect()
    {
        Network.Disconnect();
        MasterServer.UnregisterHost();
    }


    [RPC]
    IEnumerator LoadLevel(string level, int levelPrefix)
    {
        Debug.Log("Loading level " + level + " with prefix " + levelPrefix);
        lastLevelPrefix = levelPrefix;

        // There is no reason to send any more data over the network on the default channel,
        // because we are about to load the level, because all those objects will get deleted anyway
        Network.SetSendingEnabled(0, false);

        // We need to stop receiving because first the level must be loaded.
        // Once the level is loaded, RPC's and other state update attached to objects in the level are allowed to fire
        Network.isMessageQueueRunning = false;

        // All network views loaded from a level will get a prefix into their NetworkViewID.
        // This will prevent old updates from clients leaking into a newly created scene.
        Network.SetLevelPrefix(levelPrefix);
        Application.LoadLevel(level);
        yield return null;
        yield return null;

        // Allow receiving data again
        Network.isMessageQueueRunning = true;
        // Now the level has been loaded and we can start sending out data
        Network.SetSendingEnabled(0, true);

        // Notify our objects that the level and the network is ready
        Object[] go = Object.FindObjectsOfType(typeof(Transform));
        var go_len = go.Length;

        for (var i = 0; i < go_len; i++)
        {
            (go[i] as Transform).SendMessage("OnNetworkLoadedLevel", SendMessageOptions.DontRequireReceiver);
        }
    }

 void OnConnectedToServer() {
	// Notify our objects that the level and the network is ready
     foreach (GameObject go in Object.FindObjectsOfType(typeof(GameObject)))
     {
         go.SendMessage("OnNetworkLoadedLevel", SendMessageOptions.DontRequireReceiver);
     }
}

 void OnPlayerConnected()
 {
     canBeginGame = true;
 }

 void OnDisconnectedFromServer() {
	if (this.enabled != false)
		Application.LoadLevel(Application.loadedLevel);
	else
	{
        //NetworkLevelLoad _NetworkLevelLoad  = FindObjectOfType(NetworkLevelLoad);
        //_NetworkLevelLoad.OnDisconnectedFromServer();
        Application.LoadLevel(0);
        Debug.LogError("Disconected");
	}
}

}
